#include <my_head.h>
#include <sqlite3.h>
#define ERRLOG(msg)                                       \
    do                                                    \
    {                                                     \
        perror(msg);                                      \
        printf("%s-%s-%d", __FILE__, __func__, __LINE__); \
        exit(-1);                                         \
    } while (0)
//子进程资源处理函数
void deal_child(int x){
        wait(NULL);
}
int f = 0;    //历史记录回调函数标志位
typedef struct __MSG{
    char handle_code;
    char user_name[32];
    char text_box[256];
}msg_t;
sqlite3 *proc_init();
void do_conncet(int acceptfd, sqlite3 *my_db);
void server_registered(int acceptfd, msg_t *msg, sqlite3 *my_db);
void server_login(int acceptfd, msg_t *msg, sqlite3 *my_db);
void server_search(int acceptfd, msg_t *msg, sqlite3 *my_db);
void server_hostory(int acceptfd, msg_t *msg, sqlite3 *my_db);
int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("Usage: %s <ip> <port>\n", argv[0]);
        exit(-1);
    }
    //调用数据库初始化函数，创建数据库和历史记录和用户的表
    sqlite3 *my_db = proc_init();  //获取句柄my_db

    //创建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        ERRLOG("socket error");
    }

    //创建结构体
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t serveraddrlen = sizeof(serveraddr);

    //绑定
    if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddrlen))
    {
        ERRLOG("bind error");
    }

    //监听
    if (-1 == listen(sockfd, 5))
    {
        ERRLOG("listen error");
    }

    struct sockaddr_in clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    socklen_t clientaddrlen = sizeof(clientaddr);
    int acceptfd = 0;
    
    //int cli_num = 0;
    //循环接收
    while (1)
    {   //printf("测试00000000\n");
        acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
        if (-1 == acceptfd)
        {
            ERRLOG("accept error");
        }
        //printf("测试111111111\n");
        //如果有用户连接成功的话，创建一个子进程，专门处理这个客户端信息
        pid_t pid;
        pid = fork();
        //printf("测试22222222\n");
        if (pid == -1)
        {
            ERRLOG("fork error");
        }
        else if (pid == 0)
        {
            //子进程，循环收发处理信息
            msg_t msg;
            while(1)
            {
                do_conncet(acceptfd,my_db);
            }
            close(acceptfd);
            //子进程退出前 给父进程发射 SIGUSR1 信号
            kill(getppid(), SIGUSR1);
            exit(0);
        }
        else
        {
            //父进程
            signal(SIGUSR1, deal_child);
        }
    }
    close(sockfd);
    return 0;
}



//程序初始化的函数
sqlite3 *proc_init(){
    sqlite3 *my_db = NULL;
    char *errmsg = NULL;
    //文件存在直接打开，文件不存在则新建并打开
    int ret = sqlite3_open("lzq.db", &my_db);
    if(SQLITE_OK != ret){
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        exit(-1);
    }

    //建表  IF NOT EXISTS 表示
    //不存在就创建  如果存在就直接使用 而不是报错
    char buff[128] = {0};
    sprintf(buff, "%s", "CREATE TABLE IF NOT EXISTS usr(name TEXT PRIMARY KEY,  pass TEXT)");
    if(SQLITE_OK != (ret = sqlite3_exec(my_db, buff, NULL, NULL, &errmsg))){
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        exit(-1);
    }
    sprintf(buff, "%s", "CREATE TABLE IF NOT EXISTS record(name TEXT,  date TEXT,  word TEXT)");
    if(SQLITE_OK != (ret = sqlite3_exec(my_db, buff, NULL, NULL, &errmsg))){
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        exit(-1);
    }
    
    return my_db;
}

//处理子进程的请求操作
void do_conncet(int acceptfd, sqlite3 *my_db){
    //接收数据
    //printf("测试111111111111\n");
    msg_t msg;
    if(-1 == recv(acceptfd,&msg,sizeof(msg),0)){
        ERRLOG("recv error");
    }
    //解析
    switch (msg.handle_code)
    {
    case 'R':
        server_registered(acceptfd,&msg,my_db);
        break;
    case 'L':
        server_login(acceptfd,&msg,my_db);
        break;
    case 'S':
        //printf("测试2222222222\n");
        server_search(acceptfd,&msg,my_db);
        //printf("测试555555555\n");
        break;
    case 'H':
        //printf("测试2222222222\n");
        server_hostory(acceptfd,&msg,my_db);
        //printf("测试555555555\n");
        break;
    }
    
}
//注册函数
void server_registered(int acceptfd, msg_t *msg, sqlite3 *my_db){
    int ret = 0;
    msg_t re_msg = *msg; 
    char sql_buff[128] = {0};
    sprintf(sql_buff, "INSERT INTO usr VALUES('%s','%s')", re_msg.user_name, re_msg.text_box);
    memset(re_msg.text_box,0,sizeof(re_msg.text_box));
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, sql_buff, NULL, NULL, NULL)))
    {
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        strcat(re_msg.text_box,"用户名已存在");
        if(-1 == send(acceptfd,&re_msg,sizeof(re_msg),0)){
            ERRLOG("send error");
        }
        return;
    }
    strcat(re_msg.text_box,"注册成功");
    if(-1 == send(acceptfd,&re_msg,sizeof(re_msg),0)){
            ERRLOG("send error");
    }
}

//登录函数
void server_login(int acceptfd, msg_t *msg, sqlite3 *my_db){
    int ret = 0;
    char **result = NULL;
    int nrows = 0;
    int ncolumns = 0;
    msg_t re_msg = *msg; 
    char sql_buff[128] = {0};
    sprintf(sql_buff, "SELECT * FROM usr WHERE name='%s' AND pass='%s'",re_msg.user_name,re_msg.text_box);
    memset(re_msg.text_box,0,sizeof(re_msg.text_box));
    if(SQLITE_OK != (ret = sqlite3_get_table(my_db, sql_buff, &result, &nrows, &ncolumns, NULL))){//最后一个参数如果使用了需要自己手动释放
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        printf("查询失败\n");
        return;
    }
    if(nrows == 0){
        strcat(re_msg.text_box,"用户名和密码有误");
        if(-1 == send(acceptfd,&re_msg,sizeof(re_msg),0)){
                ERRLOG("send error");
        }
    }else{
        strcat(re_msg.text_box,"OK");
        if(-1 == send(acceptfd,&re_msg,sizeof(re_msg),0)){
                ERRLOG("send error");
        }
    }
}
void user_time_word(char *u_name,char *s_word,sqlite3 *my_db){
    char buff[128] = {0};
    time_t t;
    struct tm *tm;
    t = time(NULL);
    if(t == ((time_t)(-1))){
        ERRLOG("get time error");
    }
    tm = localtime(&t);
    if(tm == NULL){
        ERRLOG("change time error");
    }

    sprintf(buff,"%4d-%02d-%02d %02d:%02d:%02d",// week = %d
            tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,
            tm->tm_min,tm->tm_sec);  //,tm->tm_wday
    //插入数据库
    int ret = 0;
    char sql_buff[128] = {0};
    sprintf(sql_buff, "INSERT INTO record VALUES('%s','%s','%s')", u_name, buff,s_word);
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, sql_buff, NULL, NULL, NULL))){
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        printf("数据插入失败\n");
        return;
    }
    printf("数据插入成功\n"); 
}
//查询函数
void server_search(int acceptfd, msg_t *msg, sqlite3 *my_db){
    //printf("测试33333333333\n");
    msg_t re_msg = *msg;
    char line[300] = {0};
    char word[32] = {0};
    memset(word,0,32);
    strcpy(word,re_msg.text_box); //先把传过来的单词保存一份
    FILE *fd;
    char *p = NULL; 
    p = line;  
    int flag = 0;   //设置标志位，如果找到flag为1，如果没找到flag为0   
    int len = strlen(re_msg.text_box);
    if(NULL == (fd = fopen("./dict.txt","r"))){
        ERRLOG("open error");
    }
    while(fgets(line,300,fd) != NULL){
        if(0==strncmp(re_msg.text_box,line,len) && line[len]==' '){
            //找到了
            flag = 1;
            //把用户名，时间，单词插入数据库
            printf("测试-------------\n");
            user_time_word(re_msg.user_name,word,my_db);
            printf("测试++++++++++++++\n");
            p = p+len;
            while(*p == ' '){ //如果*p是空格的话,指正向后移动，退出循环则说明，找到了解释的第一个字符
                p++;    
            }
            strcpy(re_msg.text_box,p); 
            break; 
        }  
    }
    if(flag==0){
        strcpy(re_msg.text_box,"not found"); 
    }
    //找没找到都需要发送给客户端
    if(-1 == send(acceptfd,&re_msg,sizeof(re_msg),0)){
        ERRLOG("send error");
    }

}
//历史记录的回调函数
 int callback_hostory (void* arg ,int  ncolumn ,char** f_value,char** f_name){
    //标志位，执行一次说明查到了一条数据，那么需要打包发送
    int acceptfd = (int)arg;
    f++;
    msg_t  msg;
    memset(&msg,0,sizeof(msg));
    char buff[128] = {0};
    strcpy(msg.user_name,f_value[0]);
    sprintf(buff,"%s:%s",f_value[1],f_value[2]);
    strcpy(msg.text_box,buff);
    if(-1 == send(acceptfd,&msg,sizeof(msg),0)){
        ERRLOG("send error");
    }

    return 0;          //一定要注意这个回调函数一定要有返回值。。。。。。。。。
}
//历史记录
void server_hostory(int acceptfd, msg_t *msg, sqlite3 *my_db){
    //msg_t re_msg = *msg; //re_msg是msg_t的变量
    msg_t * msg_p = NULL;  
    msg_p = msg;           //msg_p是指向接收过里的msg的指针
    int ret = 0;
    char sql_buff[128] = {0};
    sprintf(sql_buff,"SELECT * FROM record WHERE name='%s'",msg_p->user_name);
     if (SQLITE_OK != (ret = sqlite3_exec(my_db, sql_buff, callback_hostory, (void *)acceptfd, NULL))){
        printf("%s(%d) : errcode:[%d]  errmsg:[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        printf("查询历史失败\n");
        return;
    }
    memset(msg_p,0,sizeof(msg_t));
    strcpy(msg_p->text_box,"over");
    printf("%s\n",msg_p->text_box);    //测试
    if(-1 == send(acceptfd,msg_p,sizeof(msg_t),0)){
        ERRLOG("send error");
    }
    printf("%d\n",f);    //测试
    f = 0;        //标志位置0，暂时没用
    printf("查询历史成功\n");
}